package com.mine.modules.vm.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.mine.common.annotation.vm.AssetsInfoAnnotation;
import com.mine.common.config.exception.MineBootException;
import com.mine.common.domain.vo.Result;
import com.mine.common.utils.AnnotationUtil;
import com.mine.common.utils.oConvertUtils;
import com.mine.modules.vm.common.constant.BizConstant;
import com.mine.modules.vm.domain.dto.*;
import com.mine.modules.vm.domain.query.AssetsPageQuery;
import com.mine.modules.vm.domain.query.FieldStatsQuery;
import com.mine.modules.vm.domain.vo.VmAssetsInfo;
import com.mine.modules.vm.entity.VmAssets;
import com.mine.modules.vm.entity.VmLayer;
import com.mine.modules.vm.entity.VmLayerElement;
import com.mine.modules.vm.entity.VmSensorElement;
import com.mine.modules.vm.mapper.VmAssetsMapper;
import com.mine.modules.vm.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xujf
 * @since 2024-09-21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VmAssetsServiceImpl extends ServiceImpl<VmAssetsMapper, VmAssets> implements IVmAssetsService, IVmBaseService {

    private final IVmSensorElementService vmSensorElementService;

    private final IVmLayerElementService vmLayerElementService;

    private final IVmLayerService vmLayerService;

    private final IThumbnail thumbnail;

    private final VmAssetsMapper vmAssetsMapper;

    @Override
    public Result<?> queryPageList(AssetsPageQuery assetsPageQuery) {
        LambdaQueryWrapper<VmAssets> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(assetsPageQuery.getAssetClassify())) {
            queryWrapper.eq(VmAssets::getAssetClassify, assetsPageQuery.getAssetClassify());
        }
        queryWrapper.like(StringUtils.isNotBlank(assetsPageQuery.getDeviceClassify()), VmAssets::getDeviceClassify, assetsPageQuery.getDeviceClassify());
        queryWrapper.eq(StringUtils.isNotBlank(assetsPageQuery.getLocation()), VmAssets::getInstallPosition, assetsPageQuery.getLocation());
        queryWrapper.eq(StringUtils.isNotBlank(assetsPageQuery.getPurpose()), VmAssets::getPurpose, assetsPageQuery.getPurpose());
        if (StringUtils.isNotBlank(assetsPageQuery.getKeywords())) {
            queryWrapper.and(wrapper -> wrapper
                    .like(VmAssets::getAssetNumber, assetsPageQuery.getKeywords())
                    .or()
                    .like(VmAssets::getAssetName, assetsPageQuery.getKeywords())
            );
        }
        if (StringUtils.isNotBlank(assetsPageQuery.getLayerId())) {
            //查询所有子项id集合
            List<String> layerIds = vmLayerService.getAllSubIdsByParentId(assetsPageQuery.getLayerId());
            Page<VmAssets> page = new Page<>(assetsPageQuery.getPageNo(), assetsPageQuery.getPageSize());
            IPage<VmAssets> pageList = vmAssetsMapper.selectPageWithElement(
                    page,
                    layerIds,
                    assetsPageQuery.getKeywords(),
                    assetsPageQuery.getAssetClassify(),
                    assetsPageQuery.getLocation(),
                    assetsPageQuery.getDeviceClassify(),
                    assetsPageQuery.getPurpose()
            );
            return Result.ok(pageList);
        } else {
            Page<VmAssets> page = new Page<>(assetsPageQuery.getPageNo(), assetsPageQuery.getPageSize());
            IPage<VmAssets> pageList = this.page(page, queryWrapper);
            return Result.ok(pageList);
        }
    }

    @Override
    public Result<?> addOrEdit(AddOrEditAssetDto vmAsse) {
        if (vmAsse == null || StringUtils.isBlank(vmAsse.getAssetName())) {
            return Result.error("参数必填！");
        }
        if (StringUtils.isEmpty(vmAsse.getId())) {
            //新增
            VmAssets vmAssets = BeanUtil.toBean(vmAsse, VmAssets.class);
            if (this.save(vmAssets)) {
                if (StringUtils.isNotBlank(vmAsse.getLayerId())) {
                    vmLayerElementService.addElement(new AddElementDto(
                            vmAsse.getLayerId(),
                            vmAssets.getId(),
                            vmAssets.getAssetNumber(),
                            vmAssets.getAssetName(),
                            BizConstant.SCENE_ELEMENT_TYPE_ASSET
                    ));
                }
                return Result.OK("添加成功！");
            } else {
                return Result.error("添加失败！");
            }
        } else {
            VmAssets vmAssets = this.getById(vmAsse.getId());
            if (vmAssets == null) {
                return Result.error("数据不存在，请刷新重试！");
            }
            String sceneLayerId = vmAssets.getSceneLayerId();
            vmAssets = BeanUtil.toBean(vmAsse, VmAssets.class);
            vmAssets.setSceneLayerId(sceneLayerId);
            if (this.updateById(vmAssets)) {
                return Result.OK("修改成功！");
            } else {
                return Result.error("修改失败！");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> delete(String id) {
        try {
            if (this.removeById(id)) {
                //删除图元表数据
                Db.lambdaUpdate(VmLayerElement.class).eq(VmLayerElement::getElementId, id).remove();
                //删除传感器关联表
                Db.lambdaUpdate(VmSensorElement.class).eq(VmSensorElement::getElementId, id).remove();
                //删除资料文件
                thumbnail.deleteBatch(id);
            }
            return Result.OK("删除成功!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> deleteBatch(String ids) {
        try {
            String[] arr = ids.split(",");
            for (String id : arr) {
                if (oConvertUtils.isNotEmpty(id)) {
                    try {
                        this.delete(id);
                    } catch (MineBootException e) {
                        if (e.getMessage() != null && e.getMessage().contains("未找到数据")) {
                            log.warn(e.getMessage());
                        } else {
                            throw e;
                        }
                    }
                }
            }
            return Result.OK("删除成功!");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error("删除失败!");
        }
    }

    @Override
    public Result<?> listAllLocation(String layerId, String keywords) {
        List<String> elementIds = getElementIdsByLayerId(layerId);
        return Result.ok(this.lambdaQuery()
                .select(VmAssets::getInstallPosition)
                .like(StringUtils.isNotBlank(keywords), VmAssets::getLocation, keywords)
                .in(!elementIds.isEmpty(), VmAssets::getId, elementIds)
                .groupBy(VmAssets::getInstallPosition)
                .isNotNull(VmAssets::getInstallPosition)
                .list()
                .stream()
                .map(VmAssets::getInstallPosition)
                .collect(Collectors.toList())
        );
    }

    private List<String> getElementIdsByLayerId(String layerId) {
        List<String> elementIds = Collections.emptyList();
        if (StringUtils.isNotBlank(layerId)) {
            List<String> layerIds = vmLayerService.getAllSubIdsByParentId(layerId);
            if (!layerIds.isEmpty()) {
                elementIds = Db.lambdaQuery(VmLayerElement.class)
                        .in(VmLayerElement::getLayerId, layerIds)
                        .list()
                        .stream()
                        .map(VmLayerElement::getElementId)
                        .collect(Collectors.toList());
            }
        }
        return elementIds;
    }

    @Override
    public Result<?> listAllAssetClassify(String layerId, String keywords) {
        List<String> elementIds = getElementIdsByLayerId(layerId);
        return Result.ok(this.lambdaQuery()
                .select(VmAssets::getAssetClassify)
                .like(StringUtils.isNotBlank(keywords), VmAssets::getAssetClassify, keywords)
                .in(!elementIds.isEmpty(), VmAssets::getId, elementIds)
                .groupBy(VmAssets::getAssetClassify)
                .isNotNull(VmAssets::getAssetClassify)
                .list()
                .stream()
                .map(VmAssets::getAssetClassify)
                .collect(Collectors.toList())
        );
    }

    @Override
    public Result<?> listAllPurpose(String layerId, String keywords) {
        List<String> elementIds = getElementIdsByLayerId(layerId);
        return Result.ok(this.lambdaQuery()
                .select(VmAssets::getPurpose)
                .like(StringUtils.isNotBlank(keywords), VmAssets::getPurpose, keywords)
                .in(!elementIds.isEmpty(), VmAssets::getId, elementIds)
                .groupBy(VmAssets::getPurpose)
                .isNotNull(VmAssets::getPurpose)
                .list()
                .stream()
                .map(VmAssets::getPurpose)
                .collect(Collectors.toList())
        );
    }

    @Override
    public Result<VmAssets> getByNumber(String assetNumber) {
        return Result.OK(lambdaQuery().eq(VmAssets::getAssetNumber, assetNumber).one());
    }

    @Override
    public Result<?> bindSceneLayerOfAssets(String deviceId, String sceneLayerId) {
        if (StringUtils.isEmpty(deviceId)) {
            return Result.error("参数不完整！");
        }
        VmAssets vmAssets = this.getById(deviceId);
        if (vmAssets == null) {
            return Result.error("资产设备不存在！");
        }
        vmAssets.setSceneLayerId(sceneLayerId);
        this.updateById(vmAssets);
        return Result.ok("操作成功！");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<?> batchBindingSensorByDeviceId(BindingSensor bindingSensor) {
        if (StringUtils.isEmpty(bindingSensor.getDeviceId()) || StringUtils.isEmpty(bindingSensor.getSensorIds())) {
            return Result.error("参数不完整！");
        }
        try {
            String[] ids = bindingSensor.getSensorIds().split(",");
            List<VmSensorElement> rows = Collections.emptyList();
            for (String sensorId : ids) {
                rows = new ArrayList<>();
                rows.add(new VmSensorElement(bindingSensor.getDeviceId(), sensorId));
                vmSensorElementService.saveBatch(rows);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new MineBootException("保存失败{" + e.getMessage() + "}");
        }
        return Result.ok("保存成功！");
    }

    @Override
    public Result<?> batchDeleteSensorByDeviceId(BindingSensor bindingSensor) {
        if (StringUtils.isEmpty(bindingSensor.getDeviceId()) || StringUtils.isEmpty(bindingSensor.getSensorIds())) {
            return Result.error("参数不完整！");
        }
        try {
            List<String> sensorIds = Arrays.asList(bindingSensor.getSensorIds().split(","));
            List<String> ids = this.vmSensorElementService.lambdaQuery()
                    .eq(VmSensorElement::getElementId, bindingSensor.getDeviceId())
                    .in(VmSensorElement::getSensorId, sensorIds)
                    .list()
                    .stream()
                    .map(VmSensorElement::getId)
                    .collect(Collectors.toList());
            vmSensorElementService.removeBatchByIds(ids);
        } catch (Exception e) {
            log.error(e.getMessage());
            return Result.error("删除失败{" + e.getMessage() + "}");
        }
        return Result.ok("删除成功！");
    }

    @Override
    public Result<?> countAssetsByLayerId(String layerId) {
        if (StringUtils.isBlank(layerId)) {
            return Result.error("参数不完整！");
        }
        return Result.ok(this.countByLayerId(layerId));
    }

    @Override
    public Result<?> countAssetsOfRegionByLayerId(String layerId) {
        List<Object> res = new ArrayList<>();
        VmLayer root = this.vmLayerService.getById(layerId);
        if (root == null) {
            return Result.error("数据不存在！");
        }
        List<VmLayer> regions = this.vmLayerService.lambdaQuery().eq(VmLayer::getParentId, layerId).list();
        if (regions.isEmpty()) {
            Map<String, Object> obj = new HashMap<>();
            obj.put("layerId", root.getId());
            obj.put("layerName", root.getLayerName());
            obj.put("total", this.countByLayerId(root.getId()));
            res.add(obj);
        } else {
            for (VmLayer region : regions) {
                Map<String, Object> obj = new HashMap<>();
                obj.put("layerId", region.getId());
                obj.put("layerName", region.getLayerName());
                obj.put("total", this.countByLayerId(region.getId()));
                res.add(obj);
            }
        }
        return Result.ok(res);
    }

    @Override
    public Result<?> getDetailsBySceneLayerId(String sceneLayerId) {
        if (StringUtils.isBlank(sceneLayerId)) {
            return Result.error("参数必填！");
        }
        VmLayerElement vmLayerElement = vmLayerElementService.lambdaQuery()
                .eq(VmLayerElement::getSceneLayerId, sceneLayerId)
                .eq(VmLayerElement::getElementType, BizConstant.SCENE_ELEMENT_TYPE_ASSET)
                .last(" limit 1 ")
                .one();
        if (vmLayerElement == null) {
            return Result.error("数据不存在！");
        }
        VmAssets vmAssets = this.getById(vmLayerElement.getElementId());
        if (vmAssets == null) {
            return Result.error("数据不存在！");
        }
        return Result.ok(vmAssets);
    }

    @Override
    public Result<?> getDetailsById(String id, String layerId) {
        VmAssets vmAssets = this.getById(id);
        if (vmAssets == null) {
            return Result.error("数据不存在！");
        }
        VmAssetsInfo vmAssetsInfo = getVmAssetsInfo(vmAssets);
        if (StringUtils.isNotBlank(layerId)) {
            VmLayerElement element = this.vmLayerElementService.lambdaQuery()
                    .eq(VmLayerElement::getLayerId, layerId)
                    .eq(VmLayerElement::getElementId, vmAssets.getId())
                    .last(" LIMIT 1 ")
                    .one();
            vmAssetsInfo.setSid(element != null ? element.getId() : "");
            vmAssetsInfo.setElementSceneLayerId(element != null ? element.getSceneLayerId() : "");
        }
        return Result.ok(vmAssetsInfo);
    }

    @Override
    public Result<?> parametricStatistical(String type, String layerId) {
        if (StringUtils.isBlank(type)) {
            return Result.error("参数不完整！");
        }
        List<Map<String, Object>> res = new ArrayList<>();
        List<String> layerIds = Collections.emptyList();
        if (StringUtils.isNotBlank(layerId)) {
            layerIds = vmLayerService.getAllSubIdsByParentId(layerId);
        }
        Field[] fields = VmAssets.class.getDeclaredFields();
        for (Field field : fields) {
            AssetsInfoAnnotation annotation = field.getAnnotation(AssetsInfoAnnotation.class);
            if (annotation != null && StringUtils.equals(type, annotation.value())) {
                Map<String, Object> obj = new HashMap<>();
                obj.put("name", annotation.tag());
                obj.put("datas", vmAssetsMapper.selectDynamicFieldStats(new FieldStatsQuery(annotation.field(), layerIds)));
                res.add(obj);
            }
        }
        return Result.ok(res);
    }

    @Override
    public Result<?> setAngleView(String id, String angleView) {
        VmAssets vmAssets = this.getById(id);
        if (vmAssets == null) {
            return Result.error("数据不存在，请刷新重试！");
        }
        vmAssets.setAngleView(angleView);
        if (this.updateById(vmAssets)) {
            return Result.ok("更新成功！");
        } else {
            return Result.error("更新失败！");
        }
    }

    @Override
    public Result<?> importExcel(MultipartFile file) {
        try {
            if (file == null || file.isEmpty()) {
                return Result.error("文件不能为空");
            }
            List<VmAssets> list = EasyExcel.read(file.getInputStream()).head(VmAssets.class)
                    .sheet().headRowNumber(3)
                    .doReadSync();
            if (list.isEmpty()) {
                return Result.error("文件数据解析为空！");
            }
            list.forEach(e -> {
                if (StringUtils.isNotEmpty(e.getAssetNumber()) && StringUtils.equals("null", e.getAssetNumber())) {
                    e.setDeviceLabel(e.getAssetName());
                    VmAssets vmAsset = this.lambdaQuery()
                            .eq(VmAssets::getAssetNumber, e.getAssetNumber())
                            .last(" LIMIT 1 ")
                            .one();
                    if (vmAsset != null) {
                        list.remove(e);
                    }
                }
            });
            this.saveBatch(list);
        } catch (IOException e) {
            log.error("导入失败", e);
            return Result.error("导入失败：" + e.getMessage());
        }
        return Result.ok("导入成功！");
    }

    private long countByLayerId(String layerId) {
        List<String> layerIds = vmLayerService.getAllSubIdsByParentId(layerId);
        List<String> elementIds = this.vmLayerElementService.lambdaQuery().in(VmLayerElement::getLayerId, layerIds).list().stream().map(VmLayerElement::getElementId).collect(Collectors.toList());
        if (elementIds.isEmpty()) {
            return 0L;
        }
        return this.lambdaQuery().in(VmAssets::getId, elementIds).count();
    }

    /**
     * 分页查询图层下未绑定的图元列表
     */
    @Override
    public Object basePageList(CommonElementListDto commonElementListDto) {
        QueryWrapper<VmAssets> queryWrapper = new QueryWrapper<>();
        try {
            if (StringUtils.isNotBlank(commonElementListDto.getKeywords())) {
                queryWrapper = AnnotationUtil.processCommonSearchKeywords(queryWrapper, VmAssets.class, commonElementListDto.getKeywords());
            }
            if (StringUtils.isNotBlank(commonElementListDto.getAssetClassify())) {
//                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmAssets.class, commonElementListDto.getAssetClassify());
                queryWrapper.eq("asset_classify", commonElementListDto.getAssetClassify());
            }
            if (StringUtils.isNotBlank(commonElementListDto.getInstallPosition())) {
                //queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmAssets.class, commonElementListDto.getInstallPosition());
                queryWrapper.eq("install_position", commonElementListDto.getInstallPosition());
            }
            List<String> ids = vmLayerElementService.getElementIdsByLayerIdOrType(commonElementListDto.getLayerId(), commonElementListDto.getElementType());
            queryWrapper.notIn(!ids.isEmpty(), "id", ids);
            Page<VmAssets> page = new Page<>(commonElementListDto.getPageNo(), commonElementListDto.getPageSize());
            return this.page(page, queryWrapper);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }

    }

    @Override
    public List<?> baseList(CommonElementListDto commonElementListDto) {
        QueryWrapper<VmAssets> queryWrapper = new QueryWrapper<>();
        try {
            if (StringUtils.isNotBlank(commonElementListDto.getKeywords())) {
                queryWrapper = AnnotationUtil.processCommonSearchKeywords(queryWrapper, VmAssets.class, commonElementListDto.getKeywords());
            }
            if (StringUtils.isNotBlank(commonElementListDto.getAssetClassify())) {
                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmAssets.class, commonElementListDto.getAssetClassify());
            }
            if (StringUtils.isNotBlank(commonElementListDto.getInstallPosition())) {
                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmAssets.class, commonElementListDto.getInstallPosition());
            }
            return this.list(queryWrapper);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<?> baseList(QueryElementDto queryElementDto) {
        QueryWrapper<VmAssets> queryWrapper = new QueryWrapper<>();
        try {
            if (StringUtils.isNotBlank(queryElementDto.getKeywords())) {
                queryWrapper = AnnotationUtil.processCommonSearchKeywords(queryWrapper, VmAssets.class, queryElementDto.getKeywords());
            }
            if (StringUtils.isNotBlank(queryElementDto.getAssetClassify())) {
                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmAssets.class, queryElementDto.getAssetClassify());
            }
            if (StringUtils.isNotBlank(queryElementDto.getInstallPosition())) {
                queryWrapper = AnnotationUtil.processCommonSearchAnd(queryWrapper, VmAssets.class, queryElementDto.getInstallPosition());
            }
            if (queryElementDto.getElementIds() != null && !queryElementDto.getElementIds().isEmpty()) {
                queryWrapper.in("id", queryElementDto.getElementIds());
            }
            return this.list(queryWrapper);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object getObjectById(String id) {
        return this.getById(id);
    }

    private VmAssetsInfo getVmAssetsInfo(VmAssets vmAssets) {
        VmAssetsInfo vmAssetsInfo = new VmAssetsInfo();
        BeanUtil.copyProperties(vmAssets, vmAssetsInfo);
        Field[] fields = VmAssets.class.getDeclaredFields();
        Map<String, Object> txInfo = new HashMap<>();
        Map<String, Object> runInfo = new HashMap<>();
        Map<String, Object> whInfo = new HashMap<>();
        Map<String, Object> bpInfo = new HashMap<>();
        Map<String, Object> lhInfo = new HashMap<>();
        Map<String, Object> hjInfo = new HashMap<>();
        Map<String, Object> jjxInfo = new HashMap<>();
        for (Field field : fields) {
            AssetsInfoAnnotation annotation = field.getAnnotation(AssetsInfoAnnotation.class);
            if (annotation != null) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(vmAssets);
                    switch (annotation.value()) {
                        case BizConstant.ASSETS_INFO_TYPE_TX:
                            txInfo.put(field.getName(), value);
                            break;
                        case BizConstant.ASSETS_INFO_TYPE_RUN:
                            runInfo.put(field.getName(), value);
                            break;
                        case BizConstant.ASSETS_INFO_TYPE_WH:
                            whInfo.put(field.getName(), value);
                            break;
                        case BizConstant.ASSETS_INFO_TYPE_BP:
                            bpInfo.put(field.getName(), value);
                            break;
                        case BizConstant.ASSETS_INFO_TYPE_LH:
                            lhInfo.put(field.getName(), value);
                            break;
                        case BizConstant.ASSETS_INFO_TYPE_HJ:
                            hjInfo.put(field.getName(), value);
                            break;
                        case BizConstant.ASSETS_INFO_TYPE_JJX:
                            jjxInfo.put(field.getName(), value);
                            break;
                    }
                } catch (IllegalAccessException e) {
                    log.error("Failed to access field value: {}", field.getName(), e);
                }
            }
        }
        // Convert maps to objects and set them in VmAssetsInfo
        if (!txInfo.isEmpty()) {
            vmAssetsInfo.setTx(txInfo);
        }
        if (!runInfo.isEmpty()) {
            vmAssetsInfo.setRun(runInfo);
        }
        if (!whInfo.isEmpty()) {
            vmAssetsInfo.setWh(whInfo);
        }
        if (!bpInfo.isEmpty()) {
            vmAssetsInfo.setBp(bpInfo);
        }
        if (!lhInfo.isEmpty()) {
            vmAssetsInfo.setLh(lhInfo);
        }
        if (!hjInfo.isEmpty()) {
            vmAssetsInfo.setHj(hjInfo);
        }
        if (!jjxInfo.isEmpty()) {
            vmAssetsInfo.setJjx(jjxInfo);
        }
        return vmAssetsInfo;
    }


}
